#include "findwords.h"
#include "finder.h"
#include "qwordsmodel.h"
#include "cancelmodel.h"
#include <QDebug>
#include <QAbstractItemModel>
#include "filterwordsmodel.h"
#include <QModelIndex>
#include <QFile>
#include <QTextStream>
#include <QProgressBar>
#include <QApplication>
#include "sd.h"

FindWords::FindWords(QProgressBar * progressBar, QObject *parent) :
	QObject(parent),
	KeyMdl(new QStandardItemModel(0, 2, this)),
	WordsMdl(new QWordsModel(this)),
	CancelMdl(new CancelModel(this)),
	progress(progressBar){
	finder = new Finder(progressBar, this);

//--Разбираюсь с моделью ключа------------------------------------------------------------
	connect(KeyMdl, SIGNAL(dataChanged(QModelIndex,QModelIndex)), SLOT(reScr()));

//--Разбираюсь с моделью слов-------------------------------------------------------------
	FilterWordsMdl = new FilterWordsModel(this);
	FilterWordsMdl->setSourceModel(WordsMdl);
	FilterWordsMdl->setDynamicSortFilter(true);
//	FilterWordsMdl->setFilterRole(Qt::StatusTipRole);
}

void FindWords::createKeyModel(const QString & s){
	text = s;
	KeyMdl->removeRows(0,KeyMdl->rowCount());
	int n;
	for(int i = 0; i < text.size(); ++i){
//		if(rez.contains(s.at(i)));else rez.append(s.at(i));
		if(((QStandardItemModel*)KeyMdl)->findItems(text.at(i)).size() == 0){
			n = KeyMdl->rowCount();
			KeyMdl->insertRow(n);
			KeyMdl->setData(KeyMdl->index(n, 0), text.at(i));
		}
	}
}

inline void FindWords::setChar(const QChar & s, const QChar & t){
	for(int i = 0; i < KeyMdl->rowCount(); ++i){
		if(KeyMdl->index(i, 0).data() == s)
			sd(KeyMdl, i, 1, t);
	}
}

void FindWords::reScr(){
	QString str = text;
	for(int j = 0; j< str.size(); ++j)
		for(int i = 0; i < KeyMdl->rowCount(); ++i)
			if(KeyMdl->index(i, 0).data().toChar() == str.at(j))
				if(!KeyMdl->index(i, 1).data().toString().isEmpty()){
					str.replace(j, 1, KeyMdl->index(i, 1).data().toString());
					break;
				}
	emit reText(str);
}

void FindWords::findWords(){
	WordsMdl->removeRows(0, WordsMdl->rowCount());
	QStringList sl;
	QString str;
	int n, l = text.size() - minWord;
	QModelIndex indx;
	for(int j = 0; j < l; ++j){
		for(int i = 15; i >= minWord; --i){
			// Ищу подходящие слова.
			str = text.mid(j, i);
			sl = finder->find(str);
			if(sl.size()){
				// Добавляю элемент верхнего уровня — кусок исходной строки.
				n = WordsMdl->rowCount();
				WordsMdl->insertRow(n);
				indx = WordsMdl->index(n, 0);
				sd(WordsMdl, n, 1, j);
				sd(WordsMdl, n, 2, str.size());
				sd(WordsMdl, n, 3, j + i);
				WordsMdl->setData(indx, str);
				WordsMdl->setData(indx, str, Qt::StatusTipRole); // Использую эту роль для фильтрации.
				// Заполняю дочерние элементы — подходящие слова.
				WordsMdl->insertColumn(0, indx);
				foreach(str, sl){
					n = WordsMdl->rowCount(indx);
					WordsMdl->insertRow(n, indx);
					WordsMdl->setData(WordsMdl->index(n, 0, indx), str);
					WordsMdl->setData(WordsMdl->index(n, 0, indx), "~", Qt::StatusTipRole); // Использую эту роль для фильтрации.
				}
			}
		}
	}
}

void FindWords::setWord(const QModelIndex & index){
	QModelIndex i = FilterWordsMdl->mapToSource(index);
	QModelIndex p = i.parent();
	if(p.isValid()
		 && p != QModelIndex()
		 && p.parent() == QModelIndex()){// Индекс указывает на дочерний элемент.
		// Получу кусок текста которому соответствует выбранное слово.
		QString text = p.data().toString();
		// Получу выбранное слово.
		QString word = i.data().toString();
		// Установлю символы в ключ.
		for(int j = 0; j < text.length(); ++j){
			setChar(text.at(j), word.at(j));
		}
		// Добавлю слово в модель отмены.
		int n = CancelMdl->rowCount();
		CancelMdl->insertRow(n);
		sd(CancelMdl, n, 0, text);
		sd(CancelMdl, n, 1, word);
		sd(CancelMdl, n, 2, WordsMdl->index(p.row(),1).data());
		sd(CancelMdl, n, 3, WordsMdl->index(p.row(),2).data());
		sd(CancelMdl, n, 4, WordsMdl->index(p.row(),3).data());

		setFilterWords();
	}
}

void FindWords::setFilterWords(){
	QString filter;
	QString filter2;
	int l = KeyMdl->rowCount();
	for(int i = 0; i < l; ++i)
		if(KeyMdl->index(i, 1).data().toString().isEmpty());else{
			filter.append(KeyMdl->index(i, 0).data().toString());
			filter2.append(KeyMdl->index(i, 1).data().toString());
		}
	FilterWordsMdl->setFilter(filter);
	FilterWordsMdl->setFilter(filter2);
	FilterWordsMdl->invalidate(); // Заставит обнвиться.
}

void FindWords::cancelSetWord(const QModelIndex & index){
	QModelIndex i = index;
	// Поправлю, если щелчёк не в первом столбце.
	if(i.column() != 0) i = CancelMdl->index(i.row(), 0);
	// Удалю символы из ключа.
	QString str = i.data().toString();
	for(int j = 0, n = KeyMdl->rowCount(); j < n; ++j){
		if(str.contains(KeyMdl->index(j, 0).data().toString()))
			sd(KeyMdl, j, 1, QString());
	}
	// Удалю слово из модели отмен.
	CancelMdl->removeRow(i.row());

	setFilterWords();
}

/** Модель для замены символов.*/
QAbstractItemModel * FindWords::keyMdl() const{
	return KeyMdl;
}

/** Модель для подходящих слов.*/
QAbstractItemModel * FindWords::wordsMdl() const{
	return FilterWordsMdl;
}

/** Модель для слов для возможности отмены.*/
QAbstractItemModel * FindWords::cancelMdl() const{
	return CancelMdl;
}

void FindWords::save(const QString & fileName){
	QFile f(fileName);
	f.open(QFile::WriteOnly);
	QModelIndex index;
	QTextStream fs(&f);
	for(int i = 0; i < WordsMdl->rowCount(); ++i){
		index = WordsMdl->index(i, 0);
		fs<<index.data().toString()<<endl;
		fs<<WordsMdl->index(i, 1).data().toString()<<endl;
		fs<<WordsMdl->index(i, 2).data().toString()<<endl;
		fs<<WordsMdl->index(i, 3).data().toString()<<endl;
		fs<<WordsMdl->rowCount(index)<<endl;
		for(int j = 0; j < WordsMdl->rowCount(index); ++j){
			fs<<WordsMdl->index(j, 0, index).data().toString()<<endl;
		}
	}
	f.close();
}

void FindWords::open(const QString & fileName){
	qDebug()<<trUtf8("Загружаю.");
	QFile f(fileName);
	f.open(QFile::ReadOnly);
	QModelIndex index;
	QTextStream fs(&f);
	QString str;
	int n;
	for(int i = 0; !fs.atEnd(); ++i){
		WordsMdl->insertRow(i);
		index = WordsMdl->index(i, 0);
		fs>>str;
		sd(WordsMdl, i, 0, str);
		fs>>str;
		sd(WordsMdl, i, 1, str);
		fs>>str;
		sd(WordsMdl, i, 2, str);
		fs>>str;
		sd(WordsMdl, i, 3, str);
		fs>>n;
		progress->setValue(0);
		progress->setMaximum(n);
		WordsMdl->insertColumns(0, 4, index);
		for(int j = 0; j < n; ++j){
			WordsMdl->insertRow(j, index);
			fs>>str;
			sd(WordsMdl, j, 0, str, index);
			progress->setValue(j);
			qApp->processEvents(); // Выполнить все события, а то цикл выполняется долго.
		}
	}
	f.close();
}
